#include "threadPool.h"

int close_pipe[2];
conn_info client[1024];
toml_table_t *conf;

void handler(int sig_num) {
  syslog(LOG_INFO, "Server shutting down");
  closelog();

  printf("\nrecive exit signal, going to exit...\n");
  int flag = 1;
  write(close_pipe[1], &flag, sizeof(int));
}

int main(int argc, char *argv[]) {
  //ARGS_CHECK(argc, 4);
  pipe(close_pipe);

  openlog("NETDISK_SERVER", LOG_PID | LOG_NDELAY, LOG_USER);

  signal(SIGPIPE, SIG_IGN);

  if (fork()) {
    close(close_pipe[0]);
    signal(SIGUSR1, handler);
    signal(SIGINT, handler);
    wait(NULL);
    exit(0);
  }
  close(close_pipe[1]);

  srand((unsigned int)time(NULL));

  conf_init(&conf);

  server_configure s;
  conf_server(&s);

  threadPool pool;
  threadPool_init(&pool, s.work_num);

  threadPool_make_worker(&pool);
  

  if (start_long_cmd_server(s.work_num,s.host,s.port2) != 0) {
      fprintf(stderr, "start_long_cmd_server failed!\n");
      exit(1);
    }

  int sockfd = tcp_init(s.host, s.port);

  int epfd = epoll_create(1);
  epoll_add(epfd, sockfd);
  epoll_add(epfd, close_pipe[0]);

  //==@wry:No.1 初始化时间轮盘|START==
  time_wheel_t *tw = init_wheel();
  ERROR_CHECK(tw, NULL, "Failed to initialize time wheel");

  int index[1024];
  int idx = 0;

  for (int i = 0; i < 1024; i++) {
    client[i].netfd = -1;
    client[i].is_alive = 0;
    index[i] = -1;
  }

  struct epoll_event ready[1024];

  while (1) {
    int ready_num = epoll_wait(epfd, ready, 1024, 1000);

    for (int i = 0; i < ready_num; ++i) {
      int fd = ready[i].data.fd;

      if (fd == sockfd) {
        // int netfd = accept(sockfd, NULL, NULL);

        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        int netfd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len);
        if (netfd > 0) {
          client[idx].addr = client_addr; // 保存地址信息
          LOG_CLIENT_EVENT(LOG_INFO, client[idx], "New connection established");
        }

        printf("client connect.\n");
        epoll_add(epfd, netfd);
        index[netfd] = idx;
        client[idx].netfd = netfd;
        client[idx].is_alive = 1;

        //==@wry:No.2 将新连接的客户端添加到时间轮盘
        printf("netfd=%d\tidx=%d\n", netfd, idx);
        printf(
            "index[netfd]=%d\tclient[idx].netfd=%d\tclient[idx].is_alive=%d\n",
            index[netfd], client[idx].netfd, client[idx].is_alive);
        client_info_t *client_info =
            (client_info_t *)malloc(sizeof(client_info_t));
        client_info->client_conn_info = client[idx]; // 复制 conn_info
        client_info->lastTime = time(NULL);          // 更新最后活跃时间
        client_info->next = NULL;
        new_connect(tw, client_info); // 添加到时间轮盘
        /* print_time_wheel(tw); */

        idx++;
      } else if (fd == close_pipe[0]) {

        pthread_mutex_lock(&pool.mutex);

        pool.is_close = 1;
        pthread_cond_broadcast(&pool.cond);

        pthread_mutex_unlock(&pool.mutex);

        for (int i = 0; i < pool.t_arr.work_num; ++i) {
          pthread_join(pool.t_arr.tid[i], NULL);
          mysql_close(pool.mysql[i]);
        }
        free(pool.mysql);
        toml_free(conf);
        //==@wry:No.3 销毁时间轮盘
        destroy_wheel(tw);

        printf("all threads have exit.\n");

      } else {
        int k = index[fd];

        TLV tlv;
        Task t;
        memset(&tlv, 0, sizeof(TLV));
        int ret_recv = recv_tlv(fd, &tlv);

        if (ret_recv == 0) {
          epoll_del(epfd, fd);
          client[k].is_alive = 0;
          LOG_CLIENT_EVENT(LOG_INFO, client[k], "Connection closed");

          //==@wry:No.4 客户端主动断开连接，更新时间轮盘
          remove_client(tw, client[k].netfd);
          print_time_wheel(tw);

          client[k].netfd = 0;
          index[fd] = -1;
          close(fd);
          continue;
        }

        //==@wry:No.5 更新客户端的最后活跃时间
        printf("before:update_client\n");
        update_client(tw, fd); // 更新客户端活跃时间
        print_time_wheel(tw);
        printf("after:update_client\n");

        pthread_mutex_lock(&pool.mutex);

        if (analyze(tlv.jwt, tlv.data, &t, fd, epfd, &pool, client, index) !=
            0) {
          pthread_mutex_unlock(&pool.mutex);
          continue;
        }

        enque(&pool.queue, t);
        pthread_cond_broadcast(&pool.cond);

        pthread_mutex_unlock(&pool.mutex);
      }
    }

    //==@wry:No.6 检查并关闭超时的客户端
    tw->current_slot = (tw->current_slot + 1) % QUEUE_SIZE; // 移动到下一个槽位
    check_timeout(tw, epfd, client, index); // 检查并关闭超时的客户端
    // print_time_wheel(tw);
  }

  return 0;
}
